<script lang="ts" setup>
import { PropType, reactive, Ref, ref, toRefs } from 'vue';
import type { UploadFile } from 'element-plus/es/components/upload/src/upload';
import { IUploadConfig } from '@/model/base-interface';
import { genFileId } from 'element-plus';

const props = defineProps({
  data: {
    type: Object as PropType<IUploadConfig>,
    required: true,
    default: () => {
      return {};
    },
  },
  fileList: {
    type: Array,
    default: () => {
      return [];
    },
  },
  disabled: {
    type: Boolean,
    default: () => false,
  },
});

const { data, fileList } = toRefs(props);
const uploadConfig = reactive(data.value);
interface RawFile {
  name: string;
  url: string;
}
const fileItem: Ref<UploadFile | null> = ref(null);
const upload = ref();
const isError = ref(false);
const errorMsg = ref('');
const handleSuccess = (response: any, file: UploadFile, list: UploadFile[]) => {
  if (uploadConfig.onSuccess) {
    uploadConfig.onSuccess(response, file, list);
  }
};
const handleError = (error: any, file: UploadFile, list: UploadFile[]) => {
  isError.value = true;
  if (uploadConfig.onError) {
    uploadConfig.onError(error, file, list);
  }
};

const handleChange = (file: UploadFile, list: UploadFile[]) => {
  if (file.status === 'ready' && uploadConfig.onAddItem) {
    fileItem.value = file;
    isError.value = false;
    errorMsg.value = '';
    isError.value = !uploadConfig.onAddItem(file, list, errorMsg, upload.value);
    if (isError.value) {
    } else {
      if (uploadConfig.onAddItemSuccess) {
        uploadConfig.onAddItemSuccess(file);
      }
    }
  }
};
const handleExceed = (files: UploadFile[]) => {
  if (uploadConfig.onExceed) {
    upload.value!.clearFiles();
    const file = files[0] as UploadRawFile;
    file.uid = genFileId();
    upload.value!.handleStart(file);
    uploadConfig.onExceed(files);
  }
};
const handleRemove = (file: UploadFile, list: UploadFile[]) => {
  if (uploadConfig.limit === 1) {
    isError.value = false;
    errorMsg.value = '';
  }
  if (uploadConfig.onRemove) {
    uploadConfig.onRemove(file, list);
  }
};
const handleBeforeUpload = (file: UploadFile) => {
  if (uploadConfig.onBeforeUpload) {
    const result = Boolean(uploadConfig.onBeforeUpload(file)) || false;
    return !result;
  }
  return true;
};
const handleBeforeRemove = (file: UploadFile, list: UploadFile[]) => {
  if (uploadConfig.onBeforeRemove) {
    uploadConfig.onBeforeRemove(file, list);
  }
};

const handleRequest = (param: UploadFile) => {
  if (uploadConfig.onHttpRequest) {
    uploadConfig.onHttpRequest(param);
  }
};
const customUpload = async (options: any): Promise<any> => {
  if (!uploadConfig.isCustomUpload) {
    throw new Error('failed');
  }

  const url = uploadConfig.action as string;
  const formData = options.formData as FormData;

  // 将 FormData 转换为可序列化的对象
  const formDataEntries: Array<{ key: string; value: any; isFile: boolean; fileName?: string; mimeType?: string }> = [];
  
  for (const [key, value] of formData.entries()) {
    if (value instanceof File) {
      // 将文件转换为 ArrayBuffer
      const arrayBuffer = await value.arrayBuffer();
      formDataEntries.push({
        key,
        value: Array.from(new Uint8Array(arrayBuffer)),
        isFile: true,
        fileName: value.name,
        mimeType: value.type
      });
    } else {
      formDataEntries.push({
        key,
        value: value as string,
        isFile: false
      });
    }
  }

  try {
    const response = await window.api.fetchData({
      method: 'post',
      url: url,
      headers: uploadConfig.headers || {},
      data: {
        formDataEntries
      }
    });

    if (response.success) {
      return response.data;
    } else {
      throw new Error(response.errorMessage || response.statusText || 'Upload failed');
    }
  } catch (error) {
    throw error;
  }
};
defineExpose({
  clear: () => {
    if (fileItem.value !== null) {
      upload.value.handleRemove(fileItem.value);
    }
  },
  setError: (msg: string) => {
    isError.value = true;
    errorMsg.value = msg;
  },
  clearError: () => {
    isError.value = false;
    errorMsg.value = '';
  },
  customUpload,
});
</script>

<template>
  <div class="multi-file-upload">
    <el-upload
      :id="uploadConfig.id || 'fileUpload'"
      ref="upload"
      :multiple="uploadConfig.multiple"
      :limit="uploadConfig.limit"
      :show-file-list="uploadConfig.showFileList || true"
      :disabled="disabled"
      :action="uploadConfig.action"
      :name="uploadConfig.name"
      :file-list="fileList"
      :auto-upload="uploadConfig.isAutoUpload"
      :accept="uploadConfig.accept"
      :on-success="handleSuccess"
      :on-exceed="handleExceed"
      :on-error="handleError"
      :on-remove="handleRemove"
      :on-change="handleChange"
      :before-upload="handleBeforeUpload"
      :before-remove="handleBeforeRemove"
      :http-request="handleRequest"
    >
      <div
        class="upload-button"
        :class="{ disabled: disabled }"
        :disabled="disabled"
      >
        {{ $t('ADD_FILE_BTN') }}
      </div>
      <template #tip>
        <div class="el-upload__tip">{{ uploadConfig.tip }}</div>
      </template>
    </el-upload>
    <span v-if="isError && errorMsg" :id="uploadConfig.errorMsgId" class="error-text">
      {{ errorMsg }}
    </span>
  </div>
</template>

<style lang="scss" scoped>
.upload-button {
  color: var(--o-color-primary);
  &.disabled {
    color: var(--o-text-color-tertiary);
  }
}
.error-text {
  color: var(--o-color-danger);
}
:deep(.el-upload-list__item.is-success .el-upload-list__item-status-label) {
  top: 0;
}
.el-upload-list__item :hover{
  background-color:  #FDFEFF;
}
</style>
